/**
 * Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
 * All rights reserved.
 *
 * For the applicable distribution terms see the license.txt -file, included in
 * the distribution.
 */

#include <QtAlgorithms>
#include <QFile>
#include <QTextStream>
#include <QApplication>
#include <QDirIterator>
#include <QDebug>

#include "declarativepurchaselistmodel.h"
#include "purchasableitembase.h"
#include "purchasableitem.h"
#include "purchasableitemnonprotected.h"

#define NONPROTECTEDCATALOG "/data/catalog.dat"
#define PROTECTEDCATALOG "/drm/data"
#define DRMPATTERN "resourceid_"

Q_DECLARE_METATYPE(IAPClient::ProductDataList) //to be able to transfer data this type with Qt::QueuedConnection

DeclarativePurchaseListModel::DeclarativePurchaseListModel(QObject *parent) :
    QAbstractListModel(parent),
    m_modelCommitRefCounter(0),
    m_requestId(KErrNotFound),
    m_isApplicationBusy(false)
{
    QHash<int, QByteArray> roles;
    roles[PurchasableItemBase::ProductIdRole] = "productid";
    roles[PurchasableItemBase::DataReqResultRole] = "reqresult";
    roles[PurchasableItemBase::TitleRole] = "tile";
    roles[PurchasableItemBase::ShortDescriptionRole] = "shortDescr";
    roles[PurchasableItemBase::LongDescriptionRole] = "longDescr";
    roles[PurchasableItemBase::PriceRole] = "price";
    roles[PurchasableItemBase::DrmProtectionRole] = "isDrm";
    roles[PurchasableItemBase::IsMetadataKnown] = "isDataKnown";
    roles[PurchasableItemBase::IsBusy] = "isBusy";
    roles[PurchasableItemBase::IsActivated] = "isActivated";
    setRoleNames(roles);

    qRegisterMetaType<IAPClient::ProductDataList>("IAPClient::ProductDataList");
    qRegisterMetaType<IAPClient::UserAndDeviceDataHash>("IAPClient::UserAndDeviceDataHash");
    connect(&m_client, SIGNAL(restorableProductsReceived (int, QString, IAPClient::ProductDataList)),
            this, SLOT(restorableProductsReceived (int, QString, IAPClient::ProductDataList)),
                    Qt::QueuedConnection);

    connect(&m_client, SIGNAL(userAndDeviceDataReceived (int, QString, IAPClient::UserAndDeviceDataHash)),
            this, SLOT(userAndDeviceDataReceived (int, QString, IAPClient::UserAndDeviceDataHash )),
                               Qt::QueuedConnection);

    readNonProtectedCatalog();
    readDRMCatalog();
}

DeclarativePurchaseListModel::~DeclarativePurchaseListModel()
{
}

QVariant DeclarativePurchaseListModel::data(const QModelIndex &index, int role) const
{
    if (index.row() < 0 || index.row() > m_data.count())
        return QVariant();

    const PurchasableItemBase *record = m_data[index.row()];
    return record->metadata(role);
}

int DeclarativePurchaseListModel::rowCount(const QModelIndex & parent) const
{
    return m_data.count();
}

bool DeclarativePurchaseListModel::drmFilter() const
{
    return true;
}

void DeclarativePurchaseListModel::setDrmFilter(bool val)
{

}

void DeclarativePurchaseListModel::classBegin()
{

}

void DeclarativePurchaseListModel::componentComplete()
{

}

void DeclarativePurchaseListModel::readNonProtectedCatalog()
{
    QString filepath = QApplication::applicationDirPath();
    filepath.append(NONPROTECTEDCATALOG);

    QFile file(filepath);
    bool result = file.open(QFile::ReadOnly);
    if(!result)
        return;

    QTextStream stream(&file);
    QString line;
    do
    {
        line = stream.readLine();
        line.trimmed();
        if(!line.isEmpty())
        {
            QStringList items = line.split("|", QString::KeepEmptyParts);
            QString productId = items[0].trimmed();
            QString url = items[1].trimmed();
            PurchasableItemNonProtected *record = new PurchasableItemNonProtected(*this, productId, url);
            beginInsertRows(QModelIndex(), rowCount(), rowCount());
            m_data << record;
            endInsertRows();
        }
    }
    while (!line.isNull());
    file.close();
}

void DeclarativePurchaseListModel::readDRMCatalog()
{
    QString filepath = QApplication::applicationDirPath();
    filepath.append(PROTECTEDCATALOG);

    QDirIterator dirit(filepath, QDir::Dirs, QDirIterator::NoIteratorFlags);
    while(dirit.hasNext())
    {
        QString dir = dirit.next();
        if(dir.contains(DRMPATTERN, Qt::CaseInsensitive))
        {
            // breakdown the !:/private/<SID>/drm/data/resourceid_<productID>/
            // extract the product to which this file belongs
            QString product;
            QStringList elem = dir.split("_", QString::SkipEmptyParts);
            elem=elem[1].split("/", QString::SkipEmptyParts);
            product = elem[0].trimmed();
            if(product.isEmpty())
                continue;

            QString productIcon(dir + "/test.png");
            PurchasableItem *record = new PurchasableItem(*this, product, productIcon);
            beginInsertRows(QModelIndex(), rowCount(), rowCount());
            m_data << record;
            endInsertRows();
        }
    }

}

bool DeclarativePurchaseListModel::setData(const QModelIndex & index, const QVariant & value, int role)
{
    if(role < PurchasableItemBase::ProductIdRole)
        return false;

    PurchasableItemBase *record = const_cast<PurchasableItemBase*>(m_data[index.row()]);
    return record->setMetadata(value, role);
}

void DeclarativePurchaseListModel::beginModelUpdate()
{
    if(!m_modelCommitRefCounter)
        beginResetModel();
    m_modelCommitRefCounter++;
}

void DeclarativePurchaseListModel::commitModelUpdate()
{
    m_modelCommitRefCounter--;
    if(m_modelCommitRefCounter < 0)
        m_modelCommitRefCounter = 0;

    if(!m_modelCommitRefCounter)
        endResetModel();
}

IAPClient& DeclarativePurchaseListModel::client()
{
    return m_client;
}

void DeclarativePurchaseListModel::buy(int index)
{
    qDebug() << "DeclarativePurchaseListModel::buy " << index;
    const_cast<PurchasableItemBase*>(record(index))->purchase();
}

PurchasableItemBase* DeclarativePurchaseListModel::record(int index) const
{
    return (m_data[index]);
}


void DeclarativePurchaseListModel::restorableProductsReceived(int requestId, QString status,
                                                              IAPClient::ProductDataList items)
{
    if(requestId != m_requestId)
        return;

    // Note , request id value is used as condition to busy indicator
    // it is needed to set the value to initial state when the request is done
    m_requestId = KErrNotFound;

    qDebug(__FUNCTION__);

    beginResetModel();
    PurchasableItemBase* item;
    foreach(item, m_data)
    {
        item->setMetadata(QVariant(false), PurchasableItemBase::IsBusy);
        if(item->isIncluded(items))
        {
            //trigger restoration
            item->restore();
        }
    }
    endResetModel();
}

void DeclarativePurchaseListModel::restoreProducts()
{
    if(m_requestId >= 0)
    {
        qDebug() << "Catalog is busy. you can set only one request at time";
        return;
    }

    qDebug(__FUNCTION__);

    m_requestId = m_client.getRestorableProducts();
    if(m_requestId < 0)
        return; // failure hapened

    beginResetModel();
    PurchasableItemBase* item;
    foreach(item, m_data)
    {
        item->setMetadata(QVariant(true), PurchasableItemBase::IsBusy);
    }
    endResetModel();
}

void DeclarativePurchaseListModel::getUserInfo()
{
    if(m_requestId >= 0)
    {
        qDebug() << "Catalog is busy. you can set only one request at time";
        return;
    }

    qDebug(__FUNCTION__);

    m_requestId = m_client.getUserAndDeviceId();
    if(m_requestId < 0)
        return; // failure hapened
        
    m_isApplicationBusy = true;
    emit applicationBusyChanged();
}

void DeclarativePurchaseListModel::userAndDeviceDataReceived (int requestId, QString status,
                                                              IAPClient::UserAndDeviceDataHash userdata)
{
    if(requestId != m_requestId)
        return;

    // Note , request id value is used as condition to busy indicator
    // it is needed to set the value to initial state when the request is done
    m_requestId = KErrNotFound;
    m_isApplicationBusy = false;
    emit applicationBusyChanged();

    qDebug(__FUNCTION__);

    qDebug() << "---data begin---" ;
    qDebug() << "\t" << userdata.value("accountdigest").toString();
    qDebug() << "\t" << userdata.value("imeidigest").toString();
    qDebug() << "\t" << userdata.value("imsidigest").toString();
    qDebug() << "\t" << userdata.value("country").toString();
    qDebug() << "\t" << userdata.value("language").toString();
    qDebug() << "\t" << userdata.value("devicemodel").toString();
    qDebug() << "---end data---" ;
}

bool DeclarativePurchaseListModel::isApplicationBusy() const
{
    return m_isApplicationBusy;
}

void DeclarativePurchaseListModel::purgeProducts()
{
    QString dirName = PurchasableItemBase::getTicketDir();
    QDir dir(dirName);

    if(!dir.exists(dirName))
        return;

    bool result;
    foreach(QFileInfo info, dir.entryInfoList(QDir::NoDotAndDotDot |
                                              QDir::System |
                                              QDir::Hidden  |
                                              QDir::AllDirs |
                                              QDir::Files,
                                              QDir::DirsFirst))
    {
        result = QFile::remove(info.absoluteFilePath());
        if (!result)
        {
            break;
        }
    }
    dir.rmdir(dirName);

    beginResetModel();
    foreach(PurchasableItemBase* item, m_data)
    {
        item->setMetadata(QVariant(false), PurchasableItemBase::IsActivated);
    }
    endResetModel();
}
